package com.cn.xc.utils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * FUN: Bean tools class
 * 
 * @author sushy
 * @date 2016-3-23
 */
public class BeanUtil extends org.springframework.beans.BeanUtils {
	public static Log logger = LogFactory.getLog(BeanUtil.class);

	/**
     * bean convert to map
     *
     * @param objBean
     * @return
     */
    public static Map<?, ?> toMap(Object objBean) {
        return toMap(objBean, false); // 默认不为null才转化
    }

    /**
     * @param objBean  要转化的bean
     * @param needNull null时是否需要转化
     * @return
     */
    public static Map<?, ?> toMap(Object objBean, boolean needNull) {
        Map map = new HashMap<String, Object>();
        if (objBean == null) {
            return null;
        }
        Class<?> cls = objBean.getClass();
        PropertyDescriptor pds[] = BeanUtil.getPropertyDescriptors(cls);
        for (PropertyDescriptor pd : pds) {
            if ("class".equals(pd.getName())) {
                continue;
            }
            try {
                Method readMethod = pd.getReadMethod();
                if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                    readMethod.setAccessible(true);
                }
                Object value = readMethod.invoke(objBean, new Object[0]);
                if (value == null && !needNull) {
                    continue;
                }
                //mapBean.put(pd.getName(), value));
                /**
                 * 将值全部转化为string类型，要保持原有类型就直接使用上一行code，[具体情况具体分析]。
                 */
                map.put(pd.getName(), value == null ? value : value.toString());
            } catch (Throwable ex) {
                throw new RuntimeException("---bean convert to map happened error---", ex);
            }
        }
        return map;
    }

    /**
     * //# map convert to bean
     *
     * @param map   要转化的map，
     * @param clazz 转化的bean类型
     * @param <T>
     * @return 如果T是内部类的话，newInstance()有问题，得先创建外部类z再去new内部类，得改改~~~
     */
    public static <T> T fromMap(Map<?, ?> map, Class<T> clazz) {
        //Class<?> cls = bean.getClass();
        T bean = null;
        try {
            bean = clazz.newInstance();
            PropertyDescriptor pds[] = getPropertyDescriptors(clazz);
            for (PropertyDescriptor pd : pds) {
                if ("class".equals(pd.getName())) {
                    continue;
                }
                if (pd.getWriteMethod() == null) {
                    continue;
                }
                Object value = map.get(pd.getName());
                if (value == null) {
                    continue;
                }
                Method writeMethod = pd.getWriteMethod();
                if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                    writeMethod.setAccessible(true);
                }
                writeMethod.invoke(bean, new Object[]{value});
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("---map convert to bean happened error---", e);
        }
        return bean;
    }

	/**
	 * //# get property value
	 * 
	 * @param bean
	 * @param pd
	 * @return
	 */
	public static Object getPropertyValue(Object bean, PropertyDescriptor pd) {
		Object value = null;
		try {
			Method method = pd.getReadMethod();
			if (method != null) {
				value = method.invoke(bean);
				return value;
			}
		} catch (IllegalArgumentException e) {
			logger.error("#getter# get filed failed ！", e);
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			logger.error("#getter# get filed failed ！", e);
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			logger.error("#getter# get filed failed ！", e);
			e.printStackTrace();
		} catch (Throwable t) {
			logger.error("#getter# get filed failed ！", t);
			t.printStackTrace();
		}
		return value;
	}

	/**
	 * //# save property value
	 * 
	 * @param bean
	 * @param pd
	 * @return
	 */
	public static void setPropertyValue(Object bean, PropertyDescriptor pd, Object value) {
		try {
			if (value == null) {
				return;
			}

			// # #setter保存
			Method method = pd.getWriteMethod();
			if (method == null) {
				return;
			}

			Class<?> cls = null;
			Class<?>[] clss = method.getParameterTypes();
			if (clss != null && clss.length == 1) {
				cls = clss[0];
			}

			if (cls == null) {
				return;
			}

			if (!cls.isPrimitive()) {
				method.invoke(bean, value);
			} else if (long.class == cls) {
				method.invoke(bean, ((Long) value).longValue());
			} else if (int.class == cls) {
				method.invoke(bean, ((Integer) value).intValue());
			} else if (boolean.class == cls) {
				method.invoke(bean, ((Boolean) value).booleanValue());
			}
		} catch (IllegalArgumentException e) {
			logger.error("#setter# save filed failed ！", e);
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			logger.error("#setter# save filed failed ！", e);
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			logger.error("#setter# save filed failed ！", e);
			e.printStackTrace();
		} catch (Throwable t) {
			logger.error("#setter# save filed failed ！", t);
			t.printStackTrace();
		}

	}

}
